<!DOCTYPE html>
<html>
<head><meta charset="utf-8" />
<title>303-闭包和装饰器</title>

<script src="/lib/require/index.js"></script>
<script src="/lib/jquery/index.js"></script>

<!-- 改为引入外部样式 -->
<link rel="stylesheet" href="/css/custom.css">

<!-- Loading mathjax macro -->
<!-- Load mathjax -->
    <script src="/lib/mathjax/index.js"></script>
    <!-- MathJax configuration -->
    <script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {
            inlineMath: [ ['$','$'], ["\\(","\\)"] ],
            displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
            processEscapes: true,
            processEnvironments: true
        },
        // Center justify equations in code and markdown cells. Elsewhere
        // we use CSS to left justify single line equations in code cells.
        displayAlign: 'center',
        "HTML-CSS": {
            styles: {'.MathJax_Display': {"margin": 0}},
            linebreaks: { automatic: true }
        }
    });
    </script>
    <!-- End of mathjax configuration --></head>
<body>
<div class="toc">
<ul>
            
            
            
            
            
            
            
                        
                        
                        <li class="toc-li-2">
                            <a href="#闭包">闭包</a>
                        </li>
                    
                
            
            
            
                        
                        
                        <li class="toc-li-2">
                            <a href="#Decorator(装饰器）">Decorator(装饰器）</a>
                        </li>
                    
                
            
            
            
            
            
                        
                        
                        <li class="toc-li-3">
                            <a href="#@-语法糖">@ 语法糖</a>
                        </li>
                    
                
            
            
            
            
            
            
            
            
            
            
                        
                        
                        <li class="toc-li-3">
                            <a href="#对带参数的函数进行装饰">对带参数的函数进行装饰</a>
                        </li>
                    
                
            
                        
                        
                        <li class="toc-li-3">
                            <a href="#带参数的装饰器">带参数的装饰器</a>
                        </li>
                    
                
            
            
            
            
            
            
            
            
                        
                        
                        <li class="toc-li-3">
                            <a href="#多个装饰器">多个装饰器</a>
                        </li>
                    
                
            
            
            
            
            
            
            
            
            
            
                        
                        
                        <li class="toc-li-3">
                            <a href="#基于类的装饰器">基于类的装饰器</a>
                        </li>
                    
                
            
            
            
            
            
            
            
            </ul>
</div>
  <div tabindex="-1" id="notebook" class="border-box-sizing">
    <div class="container" id="notebook-container">

<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[31]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="c1"># 打印所有单行变量</span>
<span class="kn">from</span> <span class="nn">IPython.core.interactiveshell</span> <span class="k">import</span> <span class="n">InteractiveShell</span>
<span class="n">InteractiveShell</span><span class="o">.</span><span class="n">ast_node_interactivity</span> <span class="o">=</span> <span class="s1">&#39;all&#39;</span>
</pre></div>

</div>
</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<blockquote><p>个人理解:<br>
python一切皆对象，可以分为静态对象和动态对象。<br>
静态对象：数字，字符串(现实中的大小，颜色等)<br>
动态对象：函数(现实中各种动作，扔东西会下落，打玻璃会碎等)</p>
</blockquote>
<p>既然函数也是对象，所以函数作为其他函数的参数，或者被return</p>
<blockquote><p>前面经常用的dir()和help()就是把函数对象作为参数</p>
</blockquote>

</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="&#38381;&#21253;">&#38381;&#21253;<a class="anchor-link" href="#&#38381;&#21253;">&#182;</a></h2><blockquote><p>在一些语言中，在函数中可以（嵌套）定义另一个函数时，如果内部的函数引用了外部的函数的变量，则可能产生闭包。</p>
</blockquote>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[32]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="nb">abs</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">)</span>  <span class="c1"># --&gt;</span>
<span class="nb">abs</span>       <span class="c1"># abs(-10)是函数调用，而abs是函数本身</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[32]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>10</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[32]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&lt;function abs&gt;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[33]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="nb">abs</span><span class="o">.</span><span class="vm">__name__</span>  <span class="c1"># --&gt;</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">abs</span>       <span class="c1"># 对象指向f标签</span>
<span class="n">f</span>             <span class="c1"># --&gt;</span>
<span class="n">f</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">)</span>        <span class="c1"># --&gt;</span>
<span class="n">f</span><span class="o">.</span><span class="vm">__name__</span>    <span class="c1"># --&gt; 本质还是原来的abs对象</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[33]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;abs&#39;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[33]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&lt;function abs&gt;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[33]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>10</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[33]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;abs&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[34]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">a</span><span class="o">*</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="o">+</span> <span class="n">b</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="n">c</span>  <span class="c1"># 向上层作用域搜索a,b,c</span>
    <span class="k">return</span> <span class="n">bar</span>                   <span class="c1"># 返回一个函数对象</span>

<span class="n">y</span> <span class="o">=</span> <span class="n">foo</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>

<span class="n">y</span>            <span class="c1"># --&gt; </span>
<span class="n">y</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span>  <span class="c1"># --&gt;</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[34]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&lt;function __main__.foo.&lt;locals&gt;.bar&gt;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[34]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>94</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[35]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="n">y</span><span class="o">.</span><span class="vm">__closure__</span>                   <span class="c1"># --&gt; cell对象的元组</span>
<span class="n">y</span><span class="o">.</span><span class="vm">__closure__</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">cell_contents</span>  <span class="c1"># --&gt; 每个cell对象携带着外部参数</span>
<span class="n">y</span><span class="o">.</span><span class="vm">__closure__</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">cell_contents</span>  <span class="c1"># --&gt;</span>
<span class="n">y</span><span class="o">.</span><span class="vm">__closure__</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">cell_contents</span>  <span class="c1"># --&gt;</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[35]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>(&lt;cell at 0x7f04bc298be8: int object at 0x559466dd3f60&gt;,
 &lt;cell at 0x7f04bc298648: int object at 0x559466dd3f80&gt;,
 &lt;cell at 0x7f04bc298e58: int object at 0x559466dd3fa0&gt;)</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[35]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>2</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[35]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>3</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[35]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>4</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Decorator(&#35013;&#39280;&#22120;&#65289;">Decorator(&#35013;&#39280;&#22120;&#65289;<a class="anchor-link" href="#Decorator(&#35013;&#39280;&#22120;&#65289;">&#182;</a></h2><blockquote><p>装饰模式有很多经典的使用场景，例如插入日志、性能测试、事务处理等等，有了装饰器，就可以提取大量函数中与本身功能无关的类似代码，从而达到代码重用的目的</p>
</blockquote>
<p>装饰器通常用于在不改变原有函数代码和功能的情况下，为其添加额外的功能</p>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[36]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>                <span class="c1"># 创建基础函数</span>
    <span class="k">return</span> <span class="s1">&#39;hello world&#39;</span>

<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;i&gt;&quot;</span> <span class="o">+</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&quot;&lt;/i&gt;&quot;</span>  <span class="c1"># 调用形参</span>
    <span class="k">return</span> <span class="n">bar</span>                          <span class="c1"># 返回函数对象</span>

<span class="n">hello</span><span class="o">.</span><span class="vm">__name__</span>      <span class="c1"># --&gt;</span>
<span class="n">hello</span> <span class="o">=</span> <span class="n">foo</span><span class="p">(</span><span class="n">hello</span><span class="p">)</span>  <span class="c1"># hello变量指向了foo.&lt;locals&gt;.bar</span>
<span class="n">hello</span><span class="o">.</span><span class="vm">__name__</span>      <span class="c1"># --&gt;</span>
<span class="n">hello</span><span class="p">()</span>             <span class="c1"># --&gt; 本质是调用了foo.&lt;locals&gt;.bar</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[36]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;hello&#39;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[36]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;bar&#39;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[36]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;hello world&lt;/i&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="@-&#35821;&#27861;&#31958;">@ &#35821;&#27861;&#31958;<a class="anchor-link" href="#@-&#35821;&#27861;&#31958;">&#182;</a></h3><p>使用装饰器提供的 @ 语法糖（Syntactic Sugar）简化代码:</p>

<pre><code>@decorator  # &lt;=&gt; func = decorator(func)
def func():
    pass</code></pre>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[37]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;i&gt;&quot;</span> <span class="o">+</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&quot;&lt;/i&gt;&quot;</span>
    <span class="k">return</span> <span class="n">bar</span>

<span class="nd">@foo</span>          <span class="c1"># 语法糖会处理最近的函数等效与hello = foo(hello)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
    <span class="k">return</span> <span class="s1">&#39;hello world&#39;</span>

<span class="n">hello</span>           <span class="c1"># --&gt;</span>
<span class="n">hello</span><span class="o">.</span><span class="vm">__name__</span>  <span class="c1"># --&gt; 这里的hello只是一个指向foo.&lt;locals&gt;.bar函数的变量</span>
<span class="n">hello</span><span class="p">()</span>         <span class="c1"># --&gt;</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[37]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&lt;function __main__.foo.&lt;locals&gt;.bar&gt;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[37]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;bar&#39;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[37]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;hello world&lt;/i&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="&#23545;&#24102;&#21442;&#25968;&#30340;&#20989;&#25968;&#36827;&#34892;&#35013;&#39280;">&#23545;&#24102;&#21442;&#25968;&#30340;&#20989;&#25968;&#36827;&#34892;&#35013;&#39280;<a class="anchor-link" href="#&#23545;&#24102;&#21442;&#25968;&#30340;&#20989;&#25968;&#36827;&#34892;&#35013;&#39280;">&#182;</a></h3>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[38]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;i&gt;&quot;</span> <span class="o">+</span> <span class="n">ret</span> <span class="o">+</span> <span class="s2">&quot;&lt;/i&gt;&quot;</span>
    <span class="k">return</span> <span class="n">bar</span>

<span class="nd">@foo</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">return</span> <span class="s1">&#39;hello </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>

<span class="nd">@foo</span>
<span class="k">def</span> <span class="nf">say</span><span class="p">(</span><span class="n">name1</span><span class="p">,</span> <span class="n">name2</span><span class="p">):</span>
    <span class="k">return</span> <span class="s1">&#39;hello </span><span class="si">{0}</span><span class="s1"> and </span><span class="si">{1}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name1</span><span class="p">,</span><span class="n">name2</span><span class="p">)</span>

<span class="n">hello</span><span class="p">(</span><span class="s1">&#39;python&#39;</span><span class="p">)</span>            <span class="c1"># --&gt;</span>
<span class="n">say</span><span class="p">(</span><span class="s1">&#39;python&#39;</span><span class="p">,</span> <span class="s1">&#39;markdwon&#39;</span><span class="p">)</span>  <span class="c1"># --&gt;</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[38]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;hello python&lt;/i&gt;&#39;</pre>
</div>

</div>

<div class="output_area">

<div class="prompt output_prompt">Out[38]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;hello python and markdwon&lt;/i&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="&#24102;&#21442;&#25968;&#30340;&#35013;&#39280;&#22120;">&#24102;&#21442;&#25968;&#30340;&#35013;&#39280;&#22120;<a class="anchor-link" href="#&#24102;&#21442;&#25968;&#30340;&#35013;&#39280;&#22120;">&#182;</a></h3><p>带参数的装饰器</p>

<pre><code>@foo(arg1, arg2)  # &lt;=&gt; func = foo(arg1, arg2)(func)
def func():
    pass</code></pre>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[39]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">bar_tags</span><span class="p">(</span><span class="n">tag</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
        <span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
            <span class="n">ret</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
            <span class="k">return</span> <span class="s1">&#39;&lt;&#39;</span> <span class="o">+</span> <span class="n">tag</span> <span class="o">+</span> <span class="s1">&#39;&gt;&#39;</span> <span class="o">+</span> <span class="n">ret</span> <span class="o">+</span> <span class="s1">&#39;&lt;/&#39;</span> <span class="o">+</span> <span class="n">tag</span> <span class="o">+</span> <span class="s1">&#39;&gt;&#39;</span>
        <span class="k">return</span> <span class="n">bar</span>
    <span class="k">return</span> <span class="n">foo</span>

<span class="nd">@bar_tags</span><span class="p">(</span><span class="s1">&#39;b&#39;</span><span class="p">)</span>  <span class="c1"># 根据不同参数返回不同的装饰器</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">return</span> <span class="s1">&#39;hello </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>

<span class="n">hello</span><span class="p">(</span><span class="s1">&#39;python&#39;</span><span class="p">)</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[39]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;b&gt;hello python&lt;/b&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="&#22810;&#20010;&#35013;&#39280;&#22120;">&#22810;&#20010;&#35013;&#39280;&#22120;<a class="anchor-link" href="#&#22810;&#20010;&#35013;&#39280;&#22120;">&#182;</a></h3><p>装饰器可以定义多个，离函数定义最近的装饰器先被调用</p>

<pre><code>@foo      # &lt;=&gt; func = foo(bar(func))
@bar
def func():
    pass</code></pre>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[40]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;i&gt;&quot;</span> <span class="o">+</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&quot;&lt;/i&gt;&quot;</span>
    <span class="k">return</span> <span class="n">bar</span>

<span class="k">def</span> <span class="nf">add_tag</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">bar</span><span class="p">():</span>
        <span class="k">return</span> <span class="s1">&#39;&lt;b&gt;&#39;</span> <span class="o">+</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;&lt;/b&gt;&#39;</span>
    <span class="k">return</span> <span class="n">bar</span>

<span class="nd">@foo</span>
<span class="nd">@add_tag</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
    <span class="k">return</span> <span class="s1">&#39;hello world&#39;</span>

<span class="n">hello</span><span class="p">()</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[40]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;&lt;b&gt;hello world&lt;/b&gt;&lt;/i&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="&#22522;&#20110;&#31867;&#30340;&#35013;&#39280;&#22120;">&#22522;&#20110;&#31867;&#30340;&#35013;&#39280;&#22120;<a class="anchor-link" href="#&#22522;&#20110;&#31867;&#30340;&#35013;&#39280;&#22120;">&#182;</a></h3>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[41]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">class</span> <span class="nc">Bold</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>

    <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="s1">&#39;&lt;b&gt;&#39;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;&lt;/b&gt;&#39;</span>

<span class="nd">@Bold</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">return</span> <span class="s1">&#39;hello </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">name</span>

<span class="n">hello</span><span class="p">(</span><span class="s1">&#39;world&#39;</span><span class="p">)</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[41]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;b&gt;hello world&lt;/b&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
<div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>类 Bold 有两个方法：</p>
<ul>
<li><code>__init__()</code>：它接收一个函数作为参数，也就是被装饰的函数  </li>
<li><code>__call__()</code>：让类对象可调用，就像函数调用一样，在调用被装饰函数时被调用</li>
</ul>
<blockquote><p>如果类装饰器有参数，则 <code>__init__</code>接收参数，而 <code>__call__</code> 接收 func</p>
<p>使用装饰器有一个瑕疵，就是被装饰的函数，它的函数名称已经不是原来的名称,为了消除这样的副作用，Python 中的 functool 包提供了一个 wraps 的装饰器</p>
</blockquote>

</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">In&nbsp;[44]:</div>
<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="k">class</span> <span class="nc">Tag</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tag</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tag</span> <span class="o">=</span> <span class="n">tag</span>

    <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="k">def</span> <span class="nf">wrapped</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
            <span class="k">return</span> <span class="s2">&quot;&lt;</span><span class="si">{tag}</span><span class="s2">&gt;</span><span class="si">{res}</span><span class="s2">&lt;/</span><span class="si">{tag}</span><span class="s2">&gt;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
                <span class="n">res</span><span class="o">=</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">),</span> <span class="n">tag</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">tag</span>
            <span class="p">)</span>
        <span class="k">return</span> <span class="n">wrapped</span>

<span class="nd">@Tag</span><span class="p">(</span><span class="s1">&#39;i&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="k">return</span> <span class="s1">&#39;hello </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">name</span>

<span class="n">hello</span><span class="p">(</span><span class="s1">&#39;world&#39;</span><span class="p">)</span>
</pre></div>

</div>
</div>
</div>

<div class="output_wrapper">
<div class="output">


<div class="output_area">

<div class="prompt output_prompt">Out[44]:</div>




<div class="output_text output_subarea output_execute_result">
<pre>&#39;&lt;i&gt;hello world&lt;/i&gt;&#39;</pre>
</div>

</div>

</div>
</div>

</div>
    </div>
  </div>
</body>

 


</html>
